# -*- coding: utf-8 -*-
from SerialWork import SerialWork
from PyQt5.QtCore import pyqtSignal, QObject, QTimer
import struct

frameHeader = b'\xAA\x55\x01'

class SerialStm32(QObject):
  dataReceived = pyqtSignal(object)

  CODE_ERROR, CODE_TEMP1, CODE_TEMP2, CODE_RESET, CODE_MOVE = 0, 1, 2, 3, 4
  ERR_BADHEADER, ERR_BADVALUE, ERR_BADCMD, ERR_TIMEOUT = 0, 1, 2, 3

  def __init__(self, _port="/dev/ttySAC2", _baudrate=115200):
    super().__init__()
    self.serialwork = SerialWork(_port, _baudrate)
    self.serialwork.setRcvCallBack(self.dataParser)
    self.serialwork.open()

    self.jobtimer = QTimer()
    self.jobtimer.timeout.connect(self.cycleTask)
    self.jobtimer.start(1000)

    self.flagReadData = False
    self.frameIndex = 0
    self.serialWdg = 15

    self.cycJob = 0

  def isOpen(self):
    return self.serialwork.isOpen()

  def cycleTask(self):
    if self.flagReadData == False: return

    # Check if the every cmd is answered by the stm32
    if self.serialWdg == 0:
      data = {}
      data['code'] = self.CODE_ERROR
      data['value'] = self.ERR_TIMEOUT
      self.flagReadData = False
      self.dataReceived.emit(data)
    else:
      self.serialWdg = self.serialWdg - 1

    if self.cycJob == 0:
      self.serialwork.sendData(self.sendGetTemp1())
    else:
      self.serialwork.sendData(self.sendGetTemp2())

  def setCycleJob(self, jobIndex):
    self.cycJob  = jobIndex

  def startReadData(self):
    self.serialWdg = 15
    self.flagReadData = True

  def stopReadData(self):
    self.flagReadData = False

  def openSerialPort(self):
    self.serialwork.open()

  def dataParser(self, rcvData):
    self.serialWdg = 15
    print("stm32 rcvd: " + rcvData.hex(" "))
    data = {}
    data['code'] = self.CODE_ERROR
    data['value'] = 0
    if len(rcvData) < 8 and rcvData[0:3] != frameHeader:
      data['code'] = self.CODE_ERROR
      data['value'] = self.ERR_BADHEADER
    else:
      if rcvData[3] == 0x11:
        try:
          data['value'] = struct.unpack('f',rcvData[7:11])[0]
          data['code'] = self.CODE_TEMP1
        except:
          data['value'] = self.ERR_BADVALUE
          data['code'] = self.CODE_ERROR
          #data['value'] = 70.0
          #data['code'] = self.CODE_TEMP1
      elif rcvData[3] == 0x21:
        try:
          data['value'] = struct.unpack('f',rcvData[7:11])[0]
          data['code'] = self.CODE_TEMP2
        except:
          data['value'] = self.ERR_BADVALUE
          data['code'] = self.CODE_ERROR
      elif rcvData[3] == 0x41:
         data['value'] = True
         data['code'] = self.CODE_MOVE
      elif rcvData[3] == 0x10 or rcvData[3] == 0x20 or rcvData[3] == 0x02:
        print("passed cmd:", rcvData.hex(" "))
        return
      else :
        data['code'] = self.CODE_ERROR
        data['value'] = self.ERR_BADCMD
    self.dataReceived.emit(data)

  def setRcvCallBack(self, function):
    self.dataReceived.connect(function)

  def sendCmdReset(self):
    self.frameIndex = 0
    data = frameHeader + b'\x02'
    data = data + self.getFrameIndex()
    data = data + b'\x00\x00'
    data = data + self.getCheckSum(data)
    return data

  def sendSetTemp1(self, temp):
    data =  frameHeader + b'\x10'
    data = data + self.getFrameIndex()
    data = data + b'\x00\x04' + struct.pack('f', temp)
    data = data + self.getCheckSum(data)
    return data

  def sendGetTemp1(self):
    data = frameHeader + b'\x11'
    data = data + self.getFrameIndex()
    data = data + b'\x00\x00'
    data = data + self.getCheckSum(data)
    return data

  def sendSetTemp2(self, temp):
    data = frameHeader + b'\x20'
    data = data + self.getFrameIndex()
    data = data + b'\x00\x04' + struct.pack('f', temp)
    data = data + self.getCheckSum(data)
    return data

  def sendGetTemp2(self):
    data = frameHeader + b'\x21'
    data = data + self.getFrameIndex()
    data = data + b'\x00\x00'
    data = data + self.getCheckSum(data)
    return data

  def sendMoveTo(self, position):
    data = frameHeader + b'\x41'
    data = data + self.getFrameIndex()
    data = data + b'\x00\x04' + struct.pack('f', position)
    data = data + self.getCheckSum(data)
    return data

  def getFrameIndex(self):
    curIndex = self.frameIndex
    if curIndex == 255 :
      self.frameIndex = 0
    else :
      self.frameIndex = curIndex + 1
    return curIndex.to_bytes(1,'little')

  def getCheckSum(self, cmd):
    checksum = 0
    for byte in cmd:
      checksum += byte
    checksum = checksum % 256
    return checksum.to_bytes(1,'little')

  def errorString(self, errCode):
    if errCode == 0:
      return "Bad cmd header!"
    if errCode == 1:
      return "Bad value, expect 4 bytes for float!"
    if errCode == 2:
      return "OTZ...unsupported cmd!"
    if errCode == 3:
      return "No response from hardware!"